package utilities;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import stars.enums.StarColors;
import stars.enums.StarDistributions;
import stars.enums.StarParameters;
import stars.enums.StarSystemDistributions;
import stars.enums.StarSystemNames;
import stars.enums.StarSystemParameters;
import stars.enums.StarTypeData;

import galaxies.CustomGalaxyData;
import galaxies.CustomGalaxyList;
import galaxies.enums.EarthLike;
import galaxies.enums.GalaxyDensity;
import galaxies.enums.GalaxySize;
import galaxies.enums.ResearchRate;
import galaxies.enums.SpiralArmNumbers;
import gameAppLayer.XMLData;
import gameAppLayer.enums.Constants;

import com.jme3.app.SimpleApplication;
import com.thoughtworks.xstream.XStream;

/*
 * Loads all game XML data files at game launch.  Saves them to an XMLData object
 */
public class XMLLoader {
	
	private static final Logger logger = Logger.getLogger(XMLLoader.class.getName());
	
	private XMLData data = new XMLData();	
	
	public void execute() throws IOException, ClassNotFoundException {
		//pre-defined list of files to load.  If modder wants to add events, space monsters, objects, etc., can add them to appropriate file.
		//Loads objects according to interfaces--one interface type applies to each file.  Interface for events, interface for space monsters, etc.
		
		logger.log(Level.INFO, "execute()");
		
		XStream xstream = new XStream();
		xstream.alias("galaxySize", GalaxySize.class);
		xstream.alias("earthLike", EarthLike.class);
		xstream.alias("galaxyDensity", GalaxyDensity.class);
		xstream.alias("researchRate", ResearchRate.class);
		xstream.alias("spiralArmNumbers", SpiralArmNumbers.class);
		xstream.alias("starSystemParameters", StarSystemParameters.class);
		xstream.alias("starColors", StarColors.class);
		xstream.alias("starDistributions", StarDistributions.class);
		xstream.alias("starParameters", StarParameters.class);
		xstream.alias("starTypeData", StarTypeData.class);
		xstream.alias("starSystemDistributions", StarSystemDistributions.class);
		xstream.alias("starSystemNames", StarSystemNames.class);
		xstream.alias("customGalaxy", CustomGalaxyData.class);		
		//Continue...
		
		logger.log(Level.INFO, "aliases defined");
		
		ArrayList<File> files = new ArrayList<File>();
		
		//------------------------------------------------
		//Create file objects
		
		//Galaxy files
		files.add(new File(Constants.dataPath + "//SpiralArmNumbers.xml"));
		files.add(new File(Constants.dataPath + "//ResearchRate.xml"));
		files.add(new File(Constants.dataPath + "//GalaxyDensity.xml"));
		files.add(new File(Constants.dataPath + "//EarthLike.xml"));
		files.add(new File(Constants.dataPath + "//GalaxySize.xml"));	
		files.add(new File(Constants.dataPath + "//StarSystemParameters.xml"));
		files.add(new File(Constants.dataPath + "//StarColors.xml"));
		files.add(new File(Constants.dataPath + "//StarDistributions.xml"));
		files.add(new File(Constants.dataPath + "//StarParameters.xml"));
		files.add(new File(Constants.dataPath + "//StarSystemDistributions.xml"));
		files.add(new File(Constants.dataPath + "//SystemNames.xml"));
		files.add(new File(Constants.dataPath + "//CustomGalaxies"));
		//Continue...
		
		logger.log(Level.INFO, "files created");
		//------------------------------------------------
		
		
		
		//------------------------------------------------
		logger.log(Level.INFO, "loading files");
		FileInputStream fis;
		InputStreamReader isr;
		ObjectInputStream in;
		Object obj;		
		
		//Load files
		for (File file: files) {
			if (isXML(file)) {					
				fis = new FileInputStream(file);
				isr = new InputStreamReader(fis);
				in = xstream.createObjectInputStream(isr);
					
				obj = in.readObject();
				handleObject(obj);				
			}
			else if (file.isDirectory()) {
				File[] fileList = file.listFiles();
				
				for (int i = 1; i < fileList.length; i++) {
					if (isXML(fileList[i])) {
						fis = new FileInputStream(fileList[i]);
						isr = new InputStreamReader(fis);
						in = xstream.createObjectInputStream(isr);
					
						obj = in.readObject();
						handleObject(obj);
					}
				}				
			}
		}	
	}
	
	private boolean isXML(File file) {
		int extensionPoint;
		String fileExtension;
		String fileName;
		fileName = file.getName();
		extensionPoint = fileName.lastIndexOf(".");
		fileExtension = fileName.substring(extensionPoint+1, fileName.length());
		
		if (fileExtension.equalsIgnoreCase("xml")) {
			return true;
		}
		else
			return false;
		
	}
	
	private void handleObject(Object obj) {
		Class<? extends Object> clazz = obj.getClass();
		if (clazz.equals(SpiralArmNumbers.class)) {
			SpiralArmNumbers armNums = (SpiralArmNumbers) obj;
			data.setArmNumbers(armNums);
			logger.log(Level.INFO, "handle spiralArmNumbers");			
		}
		else if (clazz.equals(ResearchRate.class)) {
			ResearchRate resRate = (ResearchRate) obj;
			data.setResearchRate(resRate);
			logger.log(Level.INFO, "handle researchRate");			
		}
		else if (clazz.equals(GalaxyDensity.class)) {
			GalaxyDensity galDensity = (GalaxyDensity) obj;
			data.setGalDensity(galDensity);
			logger.log(Level.INFO, "handle galaxyDensity");
		}
		else if (clazz.equals(EarthLike.class)) {
			EarthLike eLike = (EarthLike) obj;
			data.setEarthLike(eLike);
			logger.log(Level.INFO, "handle earthLike");
		}
		else if (clazz.equals(GalaxySize.class)) {
			GalaxySize galSize = (GalaxySize) obj;
			data.setGalSize(galSize);
			logger.log(Level.INFO, "handle galaxySize");
		}
		else if (clazz.equals(StarSystemParameters.class)) {
			StarSystemParameters starSystemParams = (StarSystemParameters) obj;
			data.setStarSystemParameters(starSystemParams);
			logger.log(Level.INFO, "handle starSystemParameters");
		}
		else if (clazz.equals(StarColors.class)) {
			StarColors starColors = (StarColors) obj;
			data.setStarColors(starColors);
			logger.log(Level.INFO, "handle starColors");
		}
		else if (clazz.equals(StarDistributions.class)) {
			StarDistributions starDists = (StarDistributions) obj;
			starDists.normalize();
			data.setStarDistributions(starDists);
			logger.log(Level.INFO, "handle starDistributions");
		}
		else if (clazz.equals(StarParameters.class)) {
			StarParameters starParams = (StarParameters) obj;
			data.setStarParameters(starParams);
			logger.log(Level.INFO, "handle starParameters");
		}
		else if (clazz.equals(StarSystemDistributions.class)) {
			StarSystemDistributions starSystemDists = (StarSystemDistributions) obj;
			starSystemDists.normalize();
			data.setStarSystemDistributions(starSystemDists);
			logger.log(Level.INFO, "handle starSystemDistributions");
		}
		else if (clazz.equals(StarSystemNames.class)) {
			StarSystemNames starSystemNames = (StarSystemNames) obj;
			data.setStarSystemNames(starSystemNames);
			logger.log(Level.INFO, "handle starSystemNames");
		}		
		else if (clazz.equals(CustomGalaxyData.class)) {
			CustomGalaxyData customGalaxyData = (CustomGalaxyData) obj;
			data.addCustomGalaxyData(customGalaxyData);			
			logger.log(Level.INFO, "handle customGalaxyData");
		}
		//Continue...		
		
	}
	
	public XMLData getData() {
		return this.data;
	}
	

}
